class Calendar {
  constructor({
    selected,
    startDate,
    endDate,
    range
  } = {}) {
    // 当前日期
    this.date = this.getDateObj(new Date()) // 当前初入日期
    // 打点信息
    this.selected = selected || [];
    // 起始时间
    this.startDate = startDate
    // 终止时间
    this.endDate = endDate
    // 是否范围选择
    this.range = range
    // 多选状态
    this.cleanMultipleStatus()
    // 每周日期
    this.weeks = {}
    this.lastHover = false
  }

  /**
   * 设置日期
   * @param {Object} date
   */
  setDate(date) {
    const selectDate = this.getDateObj(date)
    this.getWeeks(selectDate.fullDate)
  }

  /**
   * 清理多选状态
   */
  cleanMultipleStatus() {
    this.multipleStatus = {
      before: '',
      after: '',
      data: []
    }
  }

  setStartDate(startDate) {
    this.startDate = startDate
  }

  setEndDate(endDate) {
    this.endDate = endDate
  }

  getPreMonthObj(date) {
    date = fixIosDateFormat(date)
    date = new Date(date)

    const oldMonth = date.getMonth()
    date.setMonth(oldMonth - 1)
    const newMonth = date.getMonth()
    if (oldMonth !== 0 && newMonth - oldMonth === 0) {
      date.setMonth(newMonth - 1)
    }
    return this.getDateObj(date)
  }

  getNextMonthObj(date) {
    date = fixIosDateFormat(date)
    date = new Date(date)

    const oldMonth = date.getMonth()
    date.setMonth(oldMonth + 1)
    const newMonth = date.getMonth()
    if (newMonth - oldMonth > 1) {
      date.setMonth(newMonth - 1)
    }
    return this.getDateObj(date)
  }

  /**
   * 获取指定格式Date对象
   */
  getDateObj(date) {
    date = fixIosDateFormat(date)
    date = new Date(date)

    return {
      fullDate: getDate(date),
      year: date.getFullYear(),
      month: addZero(date.getMonth() + 1),
      date: addZero(date.getDate()),
      day: date.getDay()
    }
  }

  /**
   * 获取上一个月日期集合
   */
  getPreMonthDays(amount, dateObj) {
    const result = []
    for (let i = amount - 1; i >= 0; i--) {
      const month = dateObj.month - 1
      result.push({
        date: new Date(dateObj.year, month, -i).getDate(),
        month,
        disable: true
      })
    }
    return result
  }

  /**
   * 获取本月日期集合
   */
  getCurrentMonthDays(amount, dateObj) {
    const result = []
    const fullDate = this.date.fullDate
    for (let i = 1; i <= amount; i++) {
      const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
      const isToday = fullDate === currentDate
      // 获取打点信息
      const info = this.selected && this.selected.find((item) => {
        if (this.dateEqual(currentDate, item.date)) {
          return item
        }
      })

      // 日期禁用
      // eslint-disable-next-line no-unused-vars
      let disableBefore = true
      // eslint-disable-next-line no-unused-vars
      let disableAfter = true
      if (this.startDate) {
        disableBefore = dateCompare(this.startDate, currentDate)
      }

      if (this.endDate) {
        disableAfter = dateCompare(currentDate, this.endDate)
      }

      const multiples = this.multipleStatus.data
      let multiplesStatus = -1
      if (this.range && multiples) {
        multiplesStatus = multiples.findIndex((item) => {
          return this.dateEqual(item, currentDate)
        })
      }
      const checked = multiplesStatus !== -1

      result.push({
        fullDate: currentDate,
        year: dateObj.year,
        date: i,
        multiple: this.range ? checked : false,
        beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
        afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
        month: dateObj.month,
        disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(
          currentDate, this.endDate)),
        isToday,
        userChecked: false,
        extraInfo: info
      })
    }
    return result
  }

  /**
   * 获取下一个月日期集合
   */
  _getNextMonthDays(amount, dateObj) {
    const result = []
    const month = dateObj.month + 1
    for (let i = 1; i <= amount; i++) {
      result.push({
        date: i,
        month,
        disable: true
      })
    }
    return result
  }

  /**
   * 获取当前日期详情
   * @param {Object} date
   */
  getInfo(date) {
    if (!date) {
      date = new Date()
    }
    const res = this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
    return res || this.getDateObj(date)
  }

  /**
   * 比较时间是否相等
   */
  dateEqual(before, after) {
    before = new Date(fixIosDateFormat(before))
    after = new Date(fixIosDateFormat(after))
    return before.valueOf() === after.valueOf()
  }

  /**
   *  比较真实起始日期
   */

  isLogicBefore(currentDate, before, after) {
    let logicBefore = before
    if (before && after) {
      logicBefore = dateCompare(before, after) ? before : after
    }
    return this.dateEqual(logicBefore, currentDate)
  }

  isLogicAfter(currentDate, before, after) {
    let logicAfter = after
    if (before && after) {
      logicAfter = dateCompare(before, after) ? after : before
    }
    return this.dateEqual(logicAfter, currentDate)
  }

  /**
   * 获取日期范围内所有日期
   * @param {Object} begin
   * @param {Object} end
   */
  geDateAll(begin, end) {
    var arr = []
    var ab = begin.split('-')
    var ae = end.split('-')
    var db = new Date()
    db.setFullYear(ab[0], ab[1] - 1, ab[2])
    var de = new Date()
    de.setFullYear(ae[0], ae[1] - 1, ae[2])
    var unixDb = db.getTime() - 24 * 60 * 60 * 1000
    var unixDe = de.getTime() - 24 * 60 * 60 * 1000
    for (var k = unixDb; k <= unixDe;) {
      k = k + 24 * 60 * 60 * 1000
      arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
    }
    return arr
  }

  /**
   *  获取多选状态
   */
  setMultiple(fullDate) {
    if (!this.range) return

    const {
      before,
      after
    } = this.multipleStatus
    if (before && after) {
      if (!this.lastHover) {
        this.lastHover = true
        return
      }
      this.multipleStatus.before = fullDate
      this.multipleStatus.after = ''
      this.multipleStatus.data = []
      this.multipleStatus.fulldate = ''
      this.lastHover = false
    } else {
      if (!before) {
        this.multipleStatus.before = fullDate
        this.multipleStatus.after = undefined;
        this.lastHover = false
      } else {
        this.multipleStatus.after = fullDate
        if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
          this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
            .after);
        } else {
          this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus
            .before);
        }
        this.lastHover = true
      }
    }
    this.getWeeks(fullDate)
  }

  /**
   *  鼠标 hover 更新多选状态
   */
  setHoverMultiple(fullDate) {
    // 抖音小程序点击会触发hover事件，需要避免一下
    // #ifndef MP-TOUTIAO
    if (!this.range || this.lastHover) return
    const {
      before
    } = this.multipleStatus

    if (!before) {
      this.multipleStatus.before = fullDate
    } else {
      this.multipleStatus.after = fullDate
      if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
        this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
      } else {
        this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
      }
    }
    this.getWeeks(fullDate)
    // #endif
  }

  /**
   * 更新默认值多选状态
   */
  setDefaultMultiple(before, after) {
    this.multipleStatus.before = before
    this.multipleStatus.after = after
    if (before && after) {
      if (dateCompare(before, after)) {
        this.multipleStatus.data = this.geDateAll(before, after);
        this.getWeeks(after)
      } else {
        this.multipleStatus.data = this.geDateAll(after, before);
        this.getWeeks(before)
      }
    }
  }

  /**
   * 获取每周数据
   * @param {Object} dateData
   */
  getWeeks(dateData) {
    const {
      year,
      month
    } = this.getDateObj(dateData)

    const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
    const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))

    const currentMonthDayAmount = new Date(year, month, 0).getDate()
    const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))

    const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
    const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))

    const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]

    const weeks = new Array(6)
    for (let i = 0; i < calendarDays.length; i++) {
      const index = Math.floor(i / 7)
      if (!weeks[index]) {
        weeks[index] = new Array(7)
      }
      weeks[index][i % 7] = calendarDays[i]
    }

    this.calendar = calendarDays
    this.weeks = weeks
  }
}

function getDateTime(date, hideSecond) {
  return `${getDate(date)} ${getTime(date, hideSecond)}`
}

function getDate(date) {
  date = fixIosDateFormat(date)
  date = new Date(date)
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  return `${year}-${addZero(month)}-${addZero(day)}`
}

function getTime(date, hideSecond) {
  date = fixIosDateFormat(date)
  date = new Date(date)
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()
  return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
}

function addZero(num) {
  if (num < 10) {
    num = `0${num}`
  }
  return num
}

function getDefaultSecond(hideSecond) {
  return hideSecond ? '00:00' : '00:00:00'
}

function dateCompare(startDate, endDate) {
  startDate = new Date(fixIosDateFormat(startDate))
  endDate = new Date(fixIosDateFormat(endDate))
  return startDate <= endDate
}

function checkDate(date) {
  const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
  return date.match(dateReg)
}
// ios低版本15及以下，无法匹配 没有 ’秒‘ 时的情况，所以需要在末尾 秒 加上 问号
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9](:[0-5]?[0-9])?)?$/;

function fixIosDateFormat(value) {
  if (typeof value === 'string' && dateTimeReg.test(value)) {
    value = value.replace(/-/g, '/')
  }
  return value
}

export {
  Calendar,
  getDateTime,
  getDate,
  getTime,
  addZero,
  getDefaultSecond,
  dateCompare,
  checkDate,
  fixIosDateFormat
}
